#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib> //stdlib.h
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;
#define N  2
#define NUM 1024
//进程间通信---管道

void Write(int wfd)
{
    sleep(1);
    cout<<"wfd(文件描述符):"<<wfd<<endl;
    //string s("hello ,i am child,i'm writing");
    cout<<"给管道写一些消息:"<<endl;
    string s;
    cin>>s;
    pid_t childpid=getpid();
    char buffer[NUM];
    int number=0;
    while(true)
    {
        sleep(1);
        buffer[0]=0;
        snprintf(buffer,sizeof(buffer),"%s-%d-%s",s.c_str(),childpid,number++);//格式化控制
        //写入
        write(wfd,buffer,strlen(buffer));

    }
}
void Read(int rfd)
{
    cout<<"rfd(文件描述符):"<<rfd<<endl;
    char buffer[NUM];
    while(true)
    {
        buffer[0]=0;
        ssize_t n=read(rfd,buffer,sizeof(buffer));//sizeof(buffer)!=strlen(buffer)
        if(n>0)//返回读取的字节数
        {
            buffer[n] = 0; // 0 == '\0'
            cout<<"father get a message["<<getpid()<<"]:"<<buffer<<endl;
        }
        else if(n==0)//表示已经读取到文件的结尾。
        {
             printf("father read file done!\n");
            break;
        }
        else//如果发生错误则返回-1
        {
            break;
        }
    }

}
int main()
{
    //通过pipe函数创建的管道，可以获得两个文件描述符（存储在pipefd数组中）.
    //一个用于读取管道中的数据（pipefd[0]），另一个用于向管道中写入数据（pipefd[1]）
    int pipefd[N]={0};
    int n=pipe(pipefd);//打开的是内存级文件，不是磁盘级文件（open）
    if(n<0)
    {
        perror("pipe");
        return 1;
    }
    //child-w,father-r
    pid_t id=fork();
    if(id<0)
    {
        return 2;
    }
    else if(id==0)
    {
        //child
        close(pipefd[0]);//把读关了

         Write(pipefd[1]);

        close(pipefd[1]);//用完了就可以关了

        exit(0);

    }
    //father，父进程才会执行走到这里
    close(pipefd[1]);

    Read(pipefd[0]);
    close(pipefd[0]);//同上

    cout << "father close read fd: " << pipefd[0] << endl;
    sleep(5); //为了观察僵尸
    //回收子进程
    int status;
    pid_t rid=waitpid(id,&status,0);//阻塞等待
    if(rid<0)
    {
        return 3;
    }
     cout << "wait child success: " << rid << " exit code: " << ((status>>8)&0xFF) << " exit signal: " << (status&0x7F) << endl;
    //status 包含了子进程的退出状态信息，包括退出码和退出信号。在Unix系统中，子进程的退出状态是一个16位的整数，其中高8位表示退出码，低7位表示退出信号。
    //(status >> 8) & 0xFF：这是对退出码进行掩码操作，确保只获取高8位的值，即子进程的退出码。
    //status & 0x7F：这是获取子进程的退出信号（exit signal）。在Unix系统中，如果子进程是因为信号而终止的，低7位中的数值就代表了信号的编号。通过对 status 进行按位与操作，可以得到子进程的退出信号。
    sleep(5);

     cout << "father quit" << endl;
    return 0;

}